<template>
  <el-image
    class="picture-component"
    :style="{ height: pictureHeight, width: pictureWidth }"
    v-if="picUrl != null && picUrl.length > 0"
    fit="cover"
    :src="picUrlRandom"
    :preview-teleported="true"
    :preview-src-list="previewList"
  >
    <!-- 使用 default 插槽添加自定义内容 -->
    <template #placeholder>
      <div class="image-actions">
        <el-button type="danger" icon="Delete" circle></el-button>
      </div>
    </template>
    <template #error>
      <!-- 如果图片加载不出则显示这个图片 -->
      <el-image
        :class="`addBorder?'picture-component-border picture-component:'picture-component'`"
        :style="{ height: pictureHeight, width: pictureWidth }"
        fit="fill"
        :src="findPic404Url"
      ></el-image>
    </template>
  </el-image>
  <el-image
    v-else
    class="picture-component"
    :style="{ height: pictureHeight, width: pictureWidth }"
    fit="fill"
    :src="noPicUrl"
  ></el-image>
</template>

<script setup lang="ts">
/**
 * @author ljy
 * 20240810创建，用于单独展示图片组件。
 * 最后修改20240814
 * 有以下功能：
 * 1.首先能够通过父组件控制图片的宽高，如果父组件不传递宽高则用本组件的默认宽高。
 * 2.父组件传递了图片地址过来则显示相应图片，
 * （1）如果传递过来的图片地址无法加载图片则显示默认的404图片，也可以自定义404图片。
 * （2）如果没有传递图片地址过来则显示空白图片，也可以自定义该空白图片样式。
 * 3.图片地址不变时的图片刷新处理（因为图片名称不变时浏览器默认该图片已经下载，因此上传后的图片也不会在网页中刷新。例如管理账户个人头像
 * （1）可以在父组件上传成功后调用本组件暴露的fresh函数进行刷新。
 * （2）图片刷新的不足
 *   实际开发中如果图片地址不变，且在父组件中无法直接调用本组件提供的fresh图片刷新，这个时候需要父组件自己加上随机数来保证图片刷新。
 */

import { noPicSrc, noPhotoSrc, findPic404Src } from '@/api/pic';
import { computed, onMounted, ref, watch } from 'vue';
import { isBlobURL } from '@/api/utils/FileUtil';

interface Props {
  picUrl?: string; //图片地址
  pictureWidth?: string; //图片宽度
  pictureHeight?: string; //图片高度
  findPic404Url?: string; //自定义404图片地址
  noPicUrl?: string; //自定义空白图片地址
  previewEnabled?: boolean; //图片预览是否开启，默认是开启
  previewPics?: string[]; //图片预览地址。注意必须预览功能开启后该属性才能生效
  addBorder?: Boolean; //是否增加边框
}
const props = withDefaults(defineProps<Props>(), {
  pictureWidth: 'auto',
  pictureHeight: '28px',
  findPic404Url: findPic404Src,
  noPicUrl: noPicSrc,
  previewEnabled: true,
  previewPics: () => [],
  picUrl: '',
  addBorder: () => Boolean(false)
});

//图片预览功能
const previewList = computed(() => {
  if (props.previewEnabled) {
    //如果开启了预览功能
    if (props.previewPics.length > 0) {
      //如果传递有专门的预览图片集合，则使用预览图片集合
      return props.previewPics;
    } else {
      //否则使用默认的预览图片（单张）
      return [props.picUrl];
    }
  } else {
    //如果没有开启预览功能
    return [];
  }
});
//用于提供给父容器刷新图片，主要针对用户头像等上传后名称不变的情况，避免因为浏览器缓存问题不自动刷新图片
const picUrlRandom = ref<string>('');
//判断是否是blob，例如通过blob:http://localhost:9000/36ea6488-9ee8-4ce4-bd53-997fd773e425可以直接访问图片，这种方式就不需要再加随机数
//例如上传头像时，上传成功后直接用本地的图像文件来显示图片，而非调用上传到服务器的图片显示，这样就提升了性能。
// function isBlobURL(url: string) {
//   try {
//     new URL(url); // 尝试解析URL，如果无效会抛出错误
//     return url.startsWith('blob:'); // 检查URL是否以'blob:'开头
//   } catch (e) {
//     return false; // 如果URL无效，则不是Blob地址
//   }
// }
watch(
  () => {
    return props.picUrl;
  },
  //注意：实际开发中如果图片地址不变（包含表格中数据重新从服务端获取新数据后图片地址不变），该监听将无效。这个时候需要父组件自己加上随机数来保证图片刷新
  (newValue, oldValue) => {
    if (newValue && newValue.length > 0) {
      if (isBlobURL(newValue)) {
        //如果是二进制图片
        picUrlRandom.value = newValue;
      } else {
        //如果是服务器的图片地址，则加上随机数让图片刷新。
        picUrlRandom.value = newValue + '?' + Math.random();
      }
    } else {
      picUrlRandom.value = newValue;
    }
  },
  { immediate: true }
);
//提供给父组件刷新同名图片
const fresh = (): void => {
  if (props.picUrl && props.picUrl.length > 0) {
    picUrlRandom.value = props.picUrl + '?' + Math.random();
  }
};
//后面用watch替代。图片地址（用于更新图片时，如果名称图片一样，例如图片，导致图片缓存不会自动刷新）
// const picUrlRandom = computed(() => {
//   if (props.picUrl && props.picUrl.length > 0) {
//     console.log(1);
//     return props.picUrl + '?' + Math.random();
//   } else {
//     return props.picUrl;
//   }
// });
defineExpose({
  fresh
});
</script>

<style scoped>
.picture-component {
  margin-right: 5px;
}
.picture-component-border {
  border: 1px solid #ccc; /* 设置边框为1像素的灰色 */
  padding: 5px; /* 如果需要一定的内边距 */
  border-radius: 5px; /* 可选，为图片添加圆角 */
  /* border-radius: 50%; */
}
.image-slot {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 10;
}
.image-actions {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 10;
}
</style>
